package edu.pku.sei.transformation.semantics;

import java.util.ArrayList;
import java.util.List;

import edu.pku.sei.queryscript.parser.Ast.AlternativeState;
import edu.pku.sei.queryscript.parser.Ast.ArithAtomicExpr;
import edu.pku.sei.queryscript.parser.Ast.AtomicCallExpr;
import edu.pku.sei.queryscript.parser.Ast.AtomicLiteralExpr;
import edu.pku.sei.queryscript.parser.Ast.AtomicSelfExpr;
import edu.pku.sei.queryscript.parser.Ast.AtomicVariableExpr;
import edu.pku.sei.queryscript.parser.Ast.AttributeCallExpr;
import edu.pku.sei.queryscript.parser.Ast.BoolType;
import edu.pku.sei.queryscript.parser.Ast.BooleanPrimitiveLiteralExpr;
import edu.pku.sei.queryscript.parser.Ast.CallLoopExpr;
import edu.pku.sei.queryscript.parser.Ast.CallModelPropertyExpr;
import edu.pku.sei.queryscript.parser.Ast.CheckOnlyExpr;
import edu.pku.sei.queryscript.parser.Ast.CollectLoopExpr;
import edu.pku.sei.queryscript.parser.Ast.CollectionOperationCallExpr;
import edu.pku.sei.queryscript.parser.Ast.EmptyArgumentsExpr;
import edu.pku.sei.queryscript.parser.Ast.EmptyParameterExpr;
import edu.pku.sei.queryscript.parser.Ast.ExistLoopExpr;
import edu.pku.sei.queryscript.parser.Ast.ForAllLoopExpr;
import edu.pku.sei.queryscript.parser.Ast.Function;
import edu.pku.sei.queryscript.parser.Ast.FunctionCallExpr;
import edu.pku.sei.queryscript.parser.Ast.GreaterExpr;
import edu.pku.sei.queryscript.parser.Ast.IfElseState;
import edu.pku.sei.queryscript.parser.Ast.IfState;
import edu.pku.sei.queryscript.parser.Ast.IntType;
import edu.pku.sei.queryscript.parser.Ast.IntegerPrimitiveLiteralExpr;
import edu.pku.sei.queryscript.parser.Ast.LessExpr;
import edu.pku.sei.queryscript.parser.Ast.LogicRelationalExpr;
import edu.pku.sei.queryscript.parser.Ast.MinusExpr;
import edu.pku.sei.queryscript.parser.Ast.MoreArgumentsExpr;
import edu.pku.sei.queryscript.parser.Ast.MoreParametersExpr;
import edu.pku.sei.queryscript.parser.Ast.NullLiteralExpr;
import edu.pku.sei.queryscript.parser.Ast.ObjectOperationCallExpr;
import edu.pku.sei.queryscript.parser.Ast.ParenQueryExpr;
import edu.pku.sei.queryscript.parser.Ast.PlusExpr;
import edu.pku.sei.queryscript.parser.Ast.QName;
import edu.pku.sei.queryscript.parser.Ast.QueryExpr;
import edu.pku.sei.queryscript.parser.Ast.QueryState;
import edu.pku.sei.queryscript.parser.Ast.RelationalArithExpr;
import edu.pku.sei.queryscript.parser.Ast.AbstractResultVisitor;
import edu.pku.sei.queryscript.parser.Ast.SelectLoopExpr;
import edu.pku.sei.queryscript.parser.Ast.SimpleName;
import edu.pku.sei.queryscript.parser.Ast.SingleArgumentsExpr;
import edu.pku.sei.queryscript.parser.Ast.SingleParameterExpr;
import edu.pku.sei.queryscript.parser.Ast.Statements;
import edu.pku.sei.queryscript.parser.Ast.StringPrimitiveLiteralExpr;
import edu.pku.sei.queryscript.parser.Ast.StringType;
import edu.pku.sei.queryscript.parser.Ast.VariableDeclaration;

public class VariableNameVisitor extends AbstractResultVisitor
{
	public  VariableNameVisitor(){};

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(Statements n,Object o) {
		// TODO Auto-generated method stub
		
		n.getStatements().accept(this,o);
		n.getStatement().accept(this,o);

		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(AlternativeState n,Object o) {
		// TODO Auto-generated method stub
		n.getQueryExpr().accept(this,o);
		n.getStatement().accept(this,o);
		return null;
	}

	@Override
	public Object visit(QueryState n,Object o) {
		// TODO Auto-generated method stub
		return n.getQueryExpr().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(IfState n, Object o) {
		// TODO Auto-generated method stub
		n.getLogicExpr().accept(this,o);
		n.getStatements().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(IfElseState n, Object o) {
		
		n.getLogicExpr().accept(this,o);
		n.getThenStatements().accept(this,o);
		n.getElseStatements().accept(this,o);
		return null;
	}

	@Override
	public Object visit(Function n, Object o) {
		
		/*
		 * TODO:Not sure how it should be defined
		 * 		It seems to be a function declaration, then no need to parse for varname(?)
		 */
		return null;
	}

	@Override
	public Object visit(SingleParameterExpr n, Object o) {
		
		return n.getVariableDeclaration().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(MoreParametersExpr n, Object o) {
		
		n.getParametersExpr().accept(this,o);
		n.getVariableDeclaration().accept(this,o);
		return null;
	}

	@Override
	public Object visit(EmptyParameterExpr n, Object o) {
		
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(QueryExpr n, Object o) {
		
		n.getLogicExpr().accept(this,o);
		n.getQueryExpr().accept(this,o);
		return null;
		
	}

	@Override
	public Object visit(CheckOnlyExpr n, Object o) {
		
		return n.getQueryExpr().accept(this,o);
	}

	@Override
	public Object visit(edu.pku.sei.queryscript.parser.Ast.EnforceExpr n, Object o) {
		
		return n.getQueryExpr().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(edu.pku.sei.queryscript.parser.Ast.AndExpr n, Object o) {
		
		n.getRelationalExpr().accept(this,o);
		n.getLogicExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(edu.pku.sei.queryscript.parser.Ast.OrExpr n, Object o) {
		
		n.getRelationalExpr().accept(this,o);
		n.getLogicExpr().accept(this,o);
		return null;
	}

	@Override
	public Object visit(edu.pku.sei.queryscript.parser.Ast.NotExpr n, Object o) {
		
		return n.getRelationalExpr().accept(this,o);
	}

	@Override
	public Object visit(LogicRelationalExpr n, Object o) {
		
		return n.getRelationalExpr().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(edu.pku.sei.queryscript.parser.Ast.EqualExpr n, Object o) {
		
		n.getLeftArithExpr().accept(this,o);
		n.getRightArithExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(GreaterExpr n, Object o) {
		
		n.getLeftArithExpr().accept(this,o);
		n.getRightArithExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(LessExpr n, Object o) {
		
		n.getLeftArithExpr().accept(this,o);
		n.getRightArithExpr().accept(this,o);
		return null;
	}

	@Override
	public Object visit(RelationalArithExpr n, Object o) {
		
		return n.getArithExpr().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(PlusExpr n, Object o) {
		
		n.getArithExpr().accept(this,o);
		n.getAtomicExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(MinusExpr n, Object o) {
		
		n.getArithExpr().accept(this,o);
		n.getAtomicExpr().accept(this,o);
		return null;
	}

	@Override
	public Object visit(ArithAtomicExpr n, Object o) {
		
		return n.getAtomicExpr().accept(this,o);
	}

	@Override
	public Object visit(AtomicLiteralExpr n, Object o) {
		
		return n.getLiteralExpr().accept(this,o);
	}

	@Override
	public Object visit(AtomicVariableExpr n, Object o) {

		SimpleName s = n.getVariableExpr();
		ArrayList<String> strs = (ArrayList<String>)o;
		strs.add(s.toString());
		return strs;
		
		//return n.getVariableExpr().accept(this,o);
	}

	@Override
	public Object visit(AtomicSelfExpr n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(AtomicCallExpr n, Object o) {
		
		return n.getCallExpr().accept(this,o);
	}

	@Override
	public Object visit(ParenQueryExpr n, Object o) {
		
		return n.getQueryExpr().accept(this,o);
	}

	@Override
	public Object visit(StringPrimitiveLiteralExpr n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(IntegerPrimitiveLiteralExpr n, Object o) {
		
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(BooleanPrimitiveLiteralExpr n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(NullLiteralExpr n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(CallLoopExpr n, Object o) {
		
		return n.getLoopExpr().accept(this,o);
	}

	@Override
	public Object visit(CallModelPropertyExpr n, Object o) {
		
		return n.getModelPropertyExpr().accept(this,o);
	}

	@Override
	public Object visit(FunctionCallExpr n, Object o) {
		
		return n.getArgumentsExpr().accept(this,o);
	}

	@Override
	public Object visit(AttributeCallExpr n, Object o) {
		
		return n.getSimpleName().accept(this,o);
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(CollectionOperationCallExpr n, Object o) {
		
		n.getAtomicExpr().accept(this,o);
		n.getArgumentsExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(ObjectOperationCallExpr n, Object o) {
		
		n.getAtomicExpr().accept(this,o);
		n.getArgumentsExpr().accept(this,o);
		return null;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Object visit(MoreArgumentsExpr n, Object o) {
		
		n.getArgumentsExpr().accept(this,o);
		n.getLogicExpr().accept(this,o);
		return null;
	}

	@Override
	public Object visit(SingleArgumentsExpr n, Object o) {
		
		return n.getLogicExpr().accept(this,o);
	}

	@Override
	public Object visit(EmptyArgumentsExpr n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(SelectLoopExpr n, Object o) {
		/*
		 * TODO:Make sure whether only AtomicExpr is needed or not
		 */
		return n.getAtomicExpr().accept(this,o);
	}

	@Override
	public Object visit(CollectLoopExpr n, Object o) {
		
		return n.getAtomicExpr().accept(this,o);
	}

	@Override
	public Object visit(ForAllLoopExpr n, Object o) {
		
		return n.getAtomicExpr().accept(this,o);
	}

	@Override
	public Object visit(ExistLoopExpr n, Object o) {
		
		return n.getAtomicExpr().accept(this,o);
	}

	@Override
	public Object visit(VariableDeclaration n, Object o) {
		
		return n.getSimpleName().accept(this,o);
	}

	@Override
	public Object visit(BoolType n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(StringType n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(IntType n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(QName n, Object o) {
		
		return null;
	}

	@Override
	public Object visit(SimpleName n, Object o) {
		
		return null;
	}

	@Override
	public Object unimplementedVisitor(String s) {
		System.out.println(s);
		return null;
	}
}
